﻿using System;
using System.Linq.Expressions;
using BabyShop.WebSite.Exts.Extensions;
using BabyShop.WebSite.ViewModels;

namespace BabyShop.WebSite.Data.Conventions.Properties
{
    public class JqGridViewModelConvention : PropertyExpressionConventionBase
    {
        public JqGridViewModelConvention() : base(10)
        {
        }

        public override Expression BuildExpression(BuildPropertyExpressionContext context)
        {
            return null;
        }

        public Expression BuildExpression<T>(JqGridFilter jqGridFilter, ParameterExpression parameter = null)
        {
            if (jqGridFilter == null)
                return null;

            Expression expressoin = null;
            if (parameter == null)
                parameter = Expression.Parameter(typeof(T), typeof(T).Name.ToLower());
            foreach (var jqGridRule in jqGridFilter.Rules) {
                if (expressoin == null)
                    expressoin = GetExpressByRule(jqGridRule, parameter);
                else
                    expressoin.AndAlso(GetExpressByRule(jqGridRule, parameter));
            }
            return expressoin;
        }

        private static Expression GetExpressByRule(JqGridRule rule, ParameterExpression parameter)
        {
            if (rule == null || string.IsNullOrEmpty(rule.Data))
                return null;

            Type dataType = TryGetTypeByData(rule.Data);
            
            var propertyExpression = parameter.Property(rule.Field);
            if (dataType == typeof(DateTime)) {
                var date = Convert.ToDateTime(rule.Data);
                return rule.Op == "le"
                           ? Expression.LessThanOrEqual(propertyExpression, Expression.Constant(date))
                           : Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(date));
            }
            if(dataType == typeof(int)) {
                var intValue = Convert.ToInt32(rule.Data);
                return propertyExpression.Equal(Expression.Constant(intValue));
            }
            return rule.Op == "cn"
                       ? propertyExpression.Call("Contains", Expression.Constant(rule.Data))
                       : propertyExpression.Equal(Expression.Constant(rule.Data));
        }

        private static Type TryGetTypeByData(string data)
        {
            Type dataType;
            DateTime dateTime;
            int intValue;
            if (DateTime.TryParse(data, out dateTime) && dateTime != DateTime.MinValue)
                dataType = typeof(DateTime);
            else if (int.TryParse(data, out intValue))
                dataType = typeof (int);
            else
                dataType = typeof(string);

            return dataType;
        }
    }
}